using System;
using System.Collections.Generic;
using System.Text;

namespace Developex.DatabaseWrapper.Fields
{
	/// <summary>
	/// Value of aggregate function (COUNT/SUM/ABG/MAX/MIN) of arbitrary expression
	/// </summary>
	public class ExternalAggregateField<ItemType, ValueType> : FictitiousField<ValueType> where ItemType : Row, new()
	{
		#region Private fields
		private string foreignKey = null;
		private readonly List<string> tables = new List<string>();
		private readonly List<string> where = new List<string>();
		private string funcName;
		private string paramExpr;
		#endregion

		#region Properties

		/// <summary>
		/// 
		/// </summary>
		public List<string> Tables
		{
			get
			{
				return tables;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public List<string> Where
		{
			get
			{
				return where;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string ForeignKey
		{
			get
			{
				return foreignKey;
			}
			set
			{
				foreignKey = value;
			}
		}

		#endregion

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="fKey"></param>
		/// <param name="func"></param>
		/// <param name="expr"></param>
		public ExternalAggregateField(string name, FieldFlags flags, string fKey, string func, string expr)
			: base(name, flags)
		{
			foreignKey = fKey;
			funcName = func;
			paramExpr = expr;

			tables.Add(new ItemType().TableName);
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="fKey"></param>
		/// <param name="func"></param>
		/// <param name="expr"></param>
		public ExternalAggregateField(string name, string fKey, string func, string expr)
			: base(name)
		{
			foreignKey = fKey;
			funcName = func;
			paramExpr = expr;

			tables.Add(new ItemType().TableName);
		}

		/// <summary>
		/// Expression used in SELECT query
		/// </summary>
		public override string GetSelectExpression()
		{
			if (tables.Count == 0 || (foreignKey == null && where.Count == 0))
				throw new InvalidOperationException("tables.Count == 0 || (foreignKey == null && where.Count == 0)");

			string strFrom = string.Join(",", tables.ToArray());

			StringBuilder sbWhere = new StringBuilder();
			if (where.Count != 0)
				sbWhere.Append(string.Format("({0})", string.Join(")AND(", where.ToArray())));
			if (foreignKey != null)
				sbWhere.Append(string.Format("{0}({1}.{2}={3}.{4})", (where.Count != 0 ? "AND" : ""),
				 (new ItemType()).TableName_br, foreignKey, Parent.TableName_br, Parent.PrimaryKeyField.Name));

			return string.Format("(SELECT COALESCE({2}(CAST({3} AS FLOAT)), 0) FROM {0} WHERE {1})", strFrom, sbWhere, funcName, paramExpr);
		}
	}
}
